﻿////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// <copyright>Copyright 2008-2011 Andreas Huber Doenni</copyright>
// Distributed under the Microsoft Public License (Ms-PL).
// See accompanying file License.txt or copy at http://mews.codeplex.com/license.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mews.Net
{
    /// <summary>Is the base class of all commands that are pipelinable.</summary>
    /// <typeparam name="TClient">The type of the client the command is for.</typeparam>
    /// <typeparam name="TResponse">The type of the response the command will produce.</typeparam>
    /// <remarks>
    /// <para>Concrete commands never derive directly from this class, but subclass protocol-specific variants, like
    /// e.g. <see cref="Nntp.SingleLineCommand{T}"/> or <see cref="Nntp.NonPipelinableCommand{T}"/>.</para>
    /// <para>See <a href="http://www.ietf.org/rfc/rfc3977.txt">RFC 3977</a> 3.5. for a description of pipelining. Note
    /// that the concept is universal and does not just apply to the NNTP protocol.</para>
    /// <para>By definition, a pipelinable command cannot have multiple stages, so <see cref="ReceiveResponse"/> only
    /// allows for the creation of a <see cref="ResponseStream"/> object. For a multi-stage command, a
    /// <see cref="NonPipelinableCommandBase{T, U}"/> subclass must be used.</para>
    /// </remarks>
    /// <threadsafety static="true" instance="false"/>
    public abstract class PipelinableCommandBase<TClient, TResponse> : CommandBase<TClient, TResponse>
        where TClient : IClient<TClient>
        where TResponse : IResponse
    {
        internal PipelinableCommandBase()
        {
        }

        internal sealed override bool IsPipelinable
        {
            get { return true; }
        }

        internal sealed override TResponse ReceiveResponseCore(
            CreateResponseStreamCallback createResponseStreamCallback,
            CreateCommandStreamCallback createCommandStreamCallback)
        {
            return this.ReceiveResponse(createResponseStreamCallback);
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>When overridden in a derived class, receives the response to the first and only stage of the
        /// command.</summary>
        /// <param name="createResponseStreamCallback">The method that creates a stream, through which the response to
        /// the first stage command can be read, see <see cref="CreateResponseStreamCallback"/>.</param>
        /// <returns>The response.</returns>
        /// <remarks>
        /// <para>Subclass overrides simply create a <see cref="ResponseStream"/> object by calling
        /// <paramref name="createResponseStreamCallback"/> and then construct and return a response object with the
        /// data gathered through the <see cref="ResponseStream.InitialLineWords"/> and
        /// <see cref="ResponseStream.Read"/> members.</para>
        /// <para>Overrides must not swallow any exceptions thrown from <paramref name="createResponseStreamCallback"/>,
        /// or <see cref="ResponseStream"/> methods.</para>
        /// </remarks>
        protected abstract TResponse ReceiveResponse(CreateResponseStreamCallback createResponseStreamCallback);
    }
}
